package com.hivekion.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hivekion.common.core.SystemConstant;
import com.hivekion.common.entity.TreeNode;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.system.domain.SysMenu;
import com.hivekion.system.domain.vo.menu.*;
import com.hivekion.system.mapper.SysMenuMapper;
import com.hivekion.system.service.ISysMenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu>
        implements ISysMenuService {

    @Autowired
    RedisUtil redisUtil;

    @Override
    public List<SysMenu> getMenuList() {
        if (redisUtil.hasKey(SystemConstant.redis_menu_data)) {
            List<SysMenu> list =
                    JSON.parseArray(
                            redisUtil.get(SystemConstant.redis_menu_data).toString(),
                            SysMenu.class);
            return list;
        } else {
            List<SysMenu> list = this.list();
            redisUtil.set(SystemConstant.redis_menu_data, JSON.toJSONString(list));
            return list;
        }
    }

    private void updateRedis() {
        List<SysMenu> list = this.list();
        redisUtil.set(SystemConstant.redis_menu_data, JSON.toJSONString(list));
    }

    @Override
    public SysMenuModelVo getInfo(String menuId) {
        SysMenu menu = this.getById(menuId);
        if (menu == null) {
            throw new BusinessException(500, "未找到对象");
        }
        SysMenuModelVo vo = new SysMenuModelVo();
        BeanUtils.copyProperties(menu, vo);
        return vo;
    }

    @Override
    public boolean create(SysMenuCreateInputVo inputVo) {
        SysMenu menu = new SysMenu();
        BeanUtils.copyProperties(inputVo, menu);
        boolean bl = this.save(menu);
        this.updateRedis();
        return bl;
    }

    @Override
    public boolean update(SysMenuUpdateInputVo inputVo) {
        SysMenu menu = this.getById(inputVo.getId());
        if (menu == null) {
            throw new BusinessException(500, "未找到对象");
        }
        BeanUtils.copyProperties(inputVo, menu);
        boolean bl = this.updateById(menu);
        this.updateRedis();
        return bl;
    }

    @Override
    public boolean delete(String menuId) {
        List<SysMenu> children = getChildren(menuId);
        if (children != null && children.size() > 0) {
            throw new BusinessException(500, "该菜单下还有子级");
        }
        boolean bl = this.removeById(menuId);
        this.updateRedis();
        return bl;
    }

    @Override
    public List<TreeNode> getTreeSelect() {
        List<TreeNode> treeNodes = buildTreeNode(getParentMenus());
        return treeNodes;
    }

    @Override
    public List<SysMenuViewVo> getList() {
        return buildViewVo(getParentMenus());
    }

    @Override
    public boolean changeStatus(String menuId, Integer status) {
        return false;
    }

    @Override
    public List<SysMenuPermissionVo> getMenuPermission() {
        List<SysMenu> parentMenu = this.getParentMenus();
        List<SysMenuPermissionVo> data =
                parentMenu.stream()
                        .map(
                                item -> {
                                    SysMenuPermissionVo vo = new SysMenuPermissionVo();
                                    vo.setId(item.getId());
                                    vo.setMenuName(item.getMenuName());
                                    List<SysMenuPermissionVo> childrens =
                                            getChildrenMenuPermisssion(item.getId());
                                    if (childrens != null && childrens.size() > 0) {
                                        vo.setChildren(childrens);
                                    }
                                    List<SysMenuPermissionVo> buttons =
                                            getMenuButtons(item.getId());
                                    if (buttons != null && buttons.size() > 0) {
                                        vo.setButtons(buttons);
                                    }
                                    return vo;
                                })
                        .collect(Collectors.toList());
        return data;
    }

    private List<SysMenuPermissionVo> getChildrenMenuPermisssion(String parentId) {
        List<SysMenu> menuList = getChildren(parentId);
        if (menuList != null && menuList.size() > 0) {
            List<SysMenuPermissionVo> data =
                    menuList.stream()
                            .filter(m -> m.getMenuType().equals(2))
                            .sorted(Comparator.comparing(SysMenu::getSortCode))
                            .map(
                                    item -> {
                                        SysMenuPermissionVo vo = new SysMenuPermissionVo();
                                        vo.setId(item.getId());
                                        vo.setMenuName(item.getMenuName());
                                        List<SysMenuPermissionVo> childrens =
                                                getChildrenMenuPermisssion(item.getId());
                                        if (childrens != null && childrens.size() > 0) {
                                            vo.setChildren(childrens);
                                        }
                                        List<SysMenuPermissionVo> buttons =
                                                getMenuButtons(item.getId());
                                        if (buttons != null && buttons.size() > 0) {
                                            vo.setButtons(buttons);
                                        }
                                        return vo;
                                    })
                            .collect(Collectors.toList());
            return data;
        }
        return null;
    }

    private List<SysMenuPermissionVo> getMenuButtons(String parentId) {
        List<SysMenu> menuList = getChildren(parentId);
        if (menuList != null && menuList.size() > 0) {
            List<SysMenuPermissionVo> data =
                    menuList.stream()
                            .filter(m -> m.getMenuType().equals(3))
                            .sorted(Comparator.comparing(SysMenu::getSortCode))
                            .map(
                                    item -> {
                                        SysMenuPermissionVo vo = new SysMenuPermissionVo();
                                        vo.setId(item.getId());
                                        vo.setMenuName(item.getMenuName());
                                        List<SysMenuPermissionVo> childrens =
                                                getChildrenMenuPermisssion(item.getId());
                                        vo.setChildren(childrens);
                                        vo.setButtons(null);
                                        return vo;
                                    })
                            .collect(Collectors.toList());
            return data;
        }
        return null;
    }

    private List<SysMenuViewVo> buildViewVo(List<SysMenu> list) {
        List<SysMenuViewVo> nodes = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(
                    dept -> {
                        SysMenuViewVo vo = new SysMenuViewVo();
                        BeanUtils.copyProperties(dept, vo);
                        List<SysMenuViewVo> vos = getChilderenVo(dept.getId());
                        vo.setChildren(vos);
                        nodes.add(vo);
                    });
        }
        return nodes;
    }

    private List<SysMenuViewVo> getChilderenVo(String parentId) {
        List<SysMenu> list = getChildren(parentId);
        return buildViewVo(list);
    }

    private List<TreeNode> buildTreeNode(List<SysMenu> list) {
        List<TreeNode> treeNodes = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(
                    dept -> {
                        TreeNode node = new TreeNode();
                        node.setData(dept);
                        node.setKey(dept.getId());
                        node.setTitle(dept.getMenuName());
                        node.setValue(dept.getId());
                        List<TreeNode> children = getChildrenNode(dept.getId());
                        node.setLeaf(true);
                        if (children != null && children.size() > 0) {
                            node.setLeaf(false);
                            node.setChildren(children);
                        }
                        treeNodes.add(node);
                    });
        }
        return treeNodes;
    }

    private List<TreeNode> getChildrenNode(String parentId) {
        List<SysMenu> list = getChildren(parentId);
        return buildTreeNode(list);
    }

    private List<SysMenu> getParentMenus() {
        List<SysMenu> parentMenus =
                this.getMenuList().stream()
                        .filter(
                                x ->
                                        x.getParentId() == null
                                                || "0".equals(x.getParentId())
                                                || "".equals(x.getParentId()))
                        .sorted(Comparator.comparing(SysMenu::getSortCode))
                        .collect(Collectors.toList());
        return parentMenus;
    }

    private List<SysMenu> getChildren(String menuId) {
        List<SysMenu> list =
                this.getMenuList().stream()
                        .filter(
                                x ->
                                        x.getParentId() != null
                                                && x.getParentId().toString().equals(menuId))
                        .sorted(Comparator.comparing(SysMenu::getSortCode))
                        .collect(Collectors.toList());
        return list;
    }
}
